﻿using System;
using System.ServiceModel;
using NASA.BeAMartian.Extender;
using System.ComponentModel;

namespace NASA.BeAMartian.Execution
{
    public class ServiceClientExecutionItem<TChannel, TArgs> : ExecutionItem
        where TChannel : class
        where TArgs : AsyncCompletedEventArgs
    {
        public ServiceClientExecutionItem(
               ClientBase<TChannel> client,
               Action tryExecute,
               Action<EventHandler<TArgs>> onCompletedSubcribe,
               Action<EventHandler<TArgs>> onCompletedUnsubcribe,
               EventHandler<TArgs> onCompleted,
               int maxAttempts,
               Action starting,
               Action stopping)
        {
            this.Client = client;
            this.TryExecute = tryExecute;
            this.OnCompletedSubcribe = onCompletedSubcribe;
            this.OnCompletedUnsubcribe = onCompletedUnsubcribe;
            this.OnCompleted = onCompleted;
            this.MaxAttempts = maxAttempts;
            this.Starting = starting;
            this.Stopping = stopping;
        }

        public ClientBase<TChannel> Client { get; private set; }
        public Action TryExecute { get; private set; }
        public Action<EventHandler<TArgs>> OnCompletedSubcribe { get; private set; }
        public Action<EventHandler<TArgs>> OnCompletedUnsubcribe { get; private set; }
        public EventHandler<TArgs> OnCompleted { get; private set; }
        public int MaxAttempts { get; private set; }
        public Action Starting { get; private set; }
        public Action Stopping { get; private set; }
        public ClientBaseExecutionClass<TChannel, TArgs> ExecutionClass { get; private set; }

        public override void Invoke()
        {
            if (this.Starting != null)
                this.Starting.Invoke();

            this.ExecutionClass = this.Client.ExecuteAsyncRepeatedly<TChannel, TArgs>(
               this.TryExecute,
               this.OnCompletedSubcribe,
               this.OnCompletedUnsubcribe,
               this.CallCompleted,
               this.MaxAttempts);
        }

        public override void Cancel()
        {
            base.Cancel();

            if (this.ExecutionClass != null)
                this.ExecutionClass.Cancel();
        }

        public void CallCompleted(object sender, TArgs args)
        {
            if (this.Stopping != null)
                this.Stopping.Invoke();

            this.OnCompleted(sender, args);
            this.OnActionCompleted(args.Error, this.IsCanceled);
        }
    }
}
